/*******************************************************************************

                           .AVI文件解析器

********************************************************************************/
#ifndef __AVI_PARSER_H
#define __AVI_PARSER_H

#include "stdint.h" 

/*******************************************************************************
                             常量定义
********************************************************************************/
//---------------------------AVI文件基本格式-----------------------------
//使用RIFF格准：
//RIFF{'AVI'
//   主LIST:
//    LIST{'hdrl'
//       'avih'(主 AVI 信息头数据)
//       LIST{'strl'
//            'strh' (流的头信息数据)
//            'strf' (流的格式信息数据)
//            'strd' (可选的额外的头信息数据)
//            'strn' (可选的流的名字)
//       }//end LIST 'strl'
//      ... // 其他流信息
//    }end LIST 'hdrl'

//   可选LIST:
//    LIST{''
//    }end LIST ''

//   流LIST:
//   LIST{'movi' 
//        媒体流数据
//        SubChunk | LIST ('rec'
//        SubChunk1
//         SubChunk2
//        ...
//   }
//   'idx1' (可选的 AVI 索引块数据)
//}end RIFF{'AVI'

//---------------------------avi文件内标志定义--------------------------------
//按层级排列：
#define AVI_PARSER_RIFF_ID         0X46464952 //'RIFF'标志
  #define AVI_PARSER_AVI_ID        0X20495641 //'AVI'
  #define AVI_PARSER_LIST_ID       0X5453494C //'LIST'
  #define AVI_PARSER_HDRL_ID       0X6C726468 //'hdrl'信息块标志
    #define AVI_PARSER_AVIH_ID     0X68697661 //'avih'子块
    #define AVI_PARSER_STRL_ID     0X6C727473 //'strl'标志
      #define AVI_PARSER_STRH_ID   0X68727473 //strh(流头)子块
      #define AVI_PARSER_STRF_ID   0X66727473 //strf(流格式)子块
      #define AVI_PARSER_STRD_ID   0X64727473 //strd子块(可选)
      #define AVI_PARSER_STRN_ID   0X62727473 //strn子块 (可选)
    #define AVI_PARSER_VIDS_STREAM 0X73646976  //视频流'vids'标志
    #define AVI_PARSER_AUDS_STREAM 0X73647561  //音频流'auds'标志

#define AVI_PARSER_JUNK_ID         0X4B4E554A  //媒体流数据块'JUNK'段
#define AVI_PARSER_MOVI_ID         0X69766F6D  //媒体流数据块'movi'标志

//视频流类型定义
#define AVI_PARSER_VIDEO_MJPG     0X47504A4D //MJPEG格式

//音频流类型定义
#define AVI_PARSER_AUDIO_PCM     0X0001 //0X0001=PCM;
#define AVI_PARSER_AUDIO_MP2     0X0050 //0X0050=MP2;
#define AVI_PARSER_AUDIO_MP3     0X0055 //0X0055=MP3;
#define AVI_PARSER_AUDIO_AC3     0X2000 //0X2000=AC3;

//-------------------------------eAviParserStatus_t定义-------------------------
typedef enum{
  AVI_PARSER_OK = 0,     //0,成功
  AVI_PARSER_RIFF_ERR,   //1,RIFF ID读取失败
  AVI_PARSER_AVI_PARSER_ERR,    //2,AVI_PARSER  ID读取失败
  AVI_PARSER_LIST_ERR,   //3,LIST ID读取失败
  AVI_PARSER_HDRL_ERR,   //4,HDRL ID读取失败
  AVI_PARSER_AVI_PARSERH_ERR,   //5,AVI_PARSERH ID读取失败
  AVI_PARSER_STRL_ERR,   //6,STRL ID读取失败
  AVI_PARSER_STRH_ERR,   //7,STRH ID读取失败
  AVI_PARSER_STRF_ERR,   //8,STRF ID读取失败
  AVI_PARSER_MOVI_ERR,   //9,MOVI ID读取失败
  AVI_PARSER_FORMAT_ERR, //10,格式错误
  AVI_PARSER_STREAM_ERR, //11,流错误
} eAviParserStatus_t;//错误类型

/*******************************************************************************
                               结构定义
********************************************************************************/

//------------------------------音视频流数据头定义-----------------------------
//"LIST movi"后开始数据流，数据流由8字节头开始为4字节音视频跟4字节长度
//未4字节对齐需“AviParser_StreamHeader2Info(),AviParser_StreamHeader2Size()
typedef struct{
  uint8_t  Header[4];    //编码标志
  uint8_t  BlockSize[4]; //整理块大小(含本结构), 低位在前
} AVI_PARSER_STREAM_HEADER;

//---------------------------AVI文件前部相关结构定义---------------------------
//AVI 文件头部信息
typedef struct{
  uint32_t RiffID;   //RiffID=='RIFF'==0X61766968
  uint32_t FileSize; //avi文件大小(不包含最初的8字节,也RIFFID和FileSize不计算在内)
  uint32_t AVI_PARSERID;    //AVI_PARSERID=='AVI_PARSER '==0X41564920
} __attribute__((packed)) AVI_PARSER_HEADER;

//LIST 块信息
typedef struct{
  uint32_t ListID;    //ListID=='LIST'==0X4c495354
  uint32_t BlockSize; //块大小(不包含最初的8字节,ListID和BlockSize不计算在内)
  uint32_t ListType;  //LIST子块类型:hdrl(信息块)/movi(数据块)/idxl(索引块,非必须,是可选的)
} __attribute__((packed)) AVI_PARSER_LIST_HEADER;

//avih 子块信息
typedef struct{
  uint32_t BlockID;            //块标志:'avih'即0X61766968
  uint32_t BlockSize;          //块大小(不包含最初的8字节,也就是BlockID和BlockSize不计算在内)
  uint32_t SecPerFrame;        //视频帧间隔时间(单位为us)
  uint32_t MaxByteSec;         //最大数据传输率,字节/秒
  uint32_t PaddingGranularity; //数据填充的粒度
  uint32_t Flags;              //AVI文件的全局标记，比如是否含有索引块等
  uint32_t TotalFrame;         //文件总帧数
  uint32_t InitFrames;         //为交互格式指定初始帧数（非交互格式应该指定为0）
  uint32_t Streams;            //包含的数据流种类个数,通常为2
  uint32_t RefBufSize;         //建议读取本文件的缓存大小（应能容纳最大的块）默认可能是1M字节!!!
  uint32_t Width;              //图像宽
  uint32_t Height;             //图像高
  uint32_t Reserved[4];        //保留
} __attribute__((packed)) AVI_PARSER_HHEADER;

//BMP
typedef struct{
  uint32_t BmpSize;      //bmp结构体大小,包含(BmpSize在内)
  long Width;            //图像宽
  long Height;           //图像高
  uint16_t Planes;       //平面数，必须为1
  uint16_t BitCount;     //像素位数,0X0018表示24位
  uint32_t Compression;  //压缩类型，比如:MJPG/H264等
  uint32_t SizeImage;    //图像大小
  long XpixPerMeter;     //水平分辨率
  long YpixPerMeter;     //垂直分辨率
  uint32_t ClrUsed;      //实际使用了调色板中的颜色数,压缩格式中不使用
  uint32_t ClrImportant; //重要的颜色
} __attribute__((packed)) AVI_PARSER_BMP_HEADER;

//颜色表
typedef struct{
  uint8_t rgbBlue;     //蓝色的亮度(值范围为0-255)
  uint8_t rgbGreen;    //绿色的亮度(值范围为0-255)
  uint8_t rgbRed;      //红色的亮度(值范围为0-255)
  uint8_t rgbReserved; //保留，必须为0
} __attribute__((packed)) AVI_PARSER_RGBQUAD;

//strh 流头子块信息(strh∈strl)
typedef struct{
  uint32_t BlockID;    //块标志:strh==0X73747268
  uint32_t BlockSize;  //块大小(不包含最初的8字节,也就是BlockID和BlockSize不计算在内)
  uint32_t StreamType; //数据流种类，vids(0X73646976):视频;auds(0X73647561):音频
  uint32_t Handler;    //指定流的处理者，对于音视频来说就是解码器,比如MJPG/H264之类的.
  uint32_t Flags;      //标记：是否允许这个流输出？调色板是否变化？
  uint16_t Priority;   //流的优先级（当有多个相同类型的流时优先级最高的为默认流）
  uint16_t Language;   //音频的语言代号
  uint32_t InitFrames; //为交互格式指定初始帧数
  uint32_t Scale;      //数据量, 视频每桢的大小或者音频的采样大小
  uint32_t Rate;       //Scale/Rate=每秒采样数
  uint32_t Start;      //数据流开始播放的位置，单位为Scale
  uint32_t Length;     //数据流的数据量，单位为Scale
  uint32_t RefBufSize; //建议使用的缓冲区大小
  uint32_t Quality;    //解压缩质量参数，值越大，质量越好
  uint32_t SampleSize; //音频的样本大小
  struct{               //视频帧所占的矩形
    short Left;
    short Top;
    short Right;
    short Bottom;
  } Frame;
} __attribute__((packed)) AVI_PARSER_STRH_HEADER;

//对于strh,如果是视频流,strf(流格式)使STRH_BMPHEADER块
typedef struct{
  uint32_t BlockID;       //块标志,strf==0X73747266
  uint32_t BlockSize;     //块大小(不包含最初的8字节,也就是BlockID和本BlockSize不计算在内)
  AVI_PARSER_BMP_HEADER bmiHeader;   //位图信息头
  AVI_PARSER_RGBQUAD bmColors[1]; //颜色表
} __attribute__((packed)) AVI_PARSER_STRF_BMPHEADER;

//对于strh,如果是音频流,strf(流格式)使STRH_WAVHEADER块
typedef struct{
  uint32_t BlockID;    //块标志,strf==0X73747266
  uint32_t BlockSize;  //块大小(不包含最初的8字节,也就是BlockID和本BlockSize不计算在内)
  uint16_t FormatTag;  //格式标志:0X0001=PCM,0X0055=MP3...
  uint16_t Channels;   //声道数,一般为2,表示立体声
  uint32_t SampleRate; //音频采样率
  uint32_t BaudRate;   //波特率
  uint16_t BlockAlign; //数据块对齐标志
  uint16_t Size;       //该结构大小
} __attribute__((packed)) AVI_PARSER_STRF_WAVHEADER;

//---------------------------获取数据流函数定义--------------------------------
//此函数用于动态获取Avi文件持续的数据流
//pLen值>0: 读取数量，返回起始指针(NULL时结束), pLen返回实际读取数量
//pLen值为其它时:返回指针为任意, pLen返回0执行成功，非0时不支持或执行错误 
//   pLen值=0告知播放结束;pLen值=-1:移动到起始;pLen值<-1:往前跳过指定数据
//注：AviDecoder时，只要调用过一次，均需要告知播放结束。
typedef const unsigned char *(*GetAviStream_t)(void *pObj, int *pLen);

//------------------------------主信息结构体--------------------------------
//将一些重要的数据,存放在这里,方便解码
typedef struct{
  //视频相关：
  uint32_t VideoType;   //视频格式字符ID,见" AVI_PARSER_VIDEO_"定义  
  uint32_t Width;        //图像宽
  uint32_t Height;       //图像高  
  uint32_t TotalFrame;   //视频总帧数   
  uint32_t SecPerFrame;  //视频帧间隔时间(单位为us)
  //音频相关:
  uint16_t AudioType;    //音频类型: 0时无音频，有时见“AVI_PARSER_AUDIO_”定义  
  uint32_t SampleRate;   //音频采样率
  uint16_t Channels;     //声道数,一般为2,表示立体声
  uint16_t FrameMs;       //帧率时间(外部赋值)

}AviParserInfo_t;

/*******************************************************************************
                              相关函数
********************************************************************************/

//-------------------------------Avi文件解析-----------------------------------
//返回AVI_PARSER_OK解析成功(此时AviStream位于"movi"即AVI_PARSER_STREAM_HEADER)
//    其它: 错误代码
eAviParserStatus_t AviParser(AviParserInfo_t *pAviParserInfo,
                             GetAviStream_t GetAviStream, void *pObj);

//------------------------由音视频流数据头获取流信息----------------------------
//返回值为位定义: b0：0或1标志, b1:音频0视频1标志  b2:0未压缩/1压缩标志
//                b3: 0音视频帧标志,否则为pc帧, b8:未识别到标志
//即返回值 > 7时为非音视频标志.
//如01dc,01wb,第2字0或1为交替出现(不区分音频或视频), pc：改用新的调色板
//db:未压缩的视频帧, dc:压缩的视频帧, wb:未压缩音频数据, wc压缩的音频数据
uint8_t AviParser_StreamHeader2Info(const AVI_PARSER_STREAM_HEADER *pSH);
//视频帧判断
#define AviParser_InfoIsVideo(info) (((info) & 0xFA) == 0x02)
//音频帧判断
#define AviParser_InfoIsAudio(info) (((info) & 0xFA) == 0x00)
//音视频帧判断
#define AviParser_InfoIsMedia(info) ((info) < 8)
//异常头判断
#define AviParser_InfoIsErr(info) ((info) == 0xff)

//--------------------------------判断有效头---------------------------------
//高2位匹配检查
#define AviParser_IsStreamHeaderH(h,l) \
  (((h) == '0') &&  (((l) == '0') || ((l) == '1')))
//低2位匹配检查    
uint8_t AviParser_IsStreamHeaderL(uint8_t H, uint8_t L);

//---------------------------由音视频流数据头获取块大小-------------------------
//AviParser_StreamHeader2Type()非0时有效，值含头自身大小
uint32_t AviParser_StreamHeader2Size(const AVI_PARSER_STREAM_HEADER *pSH);

#endif //__AVI_PARSER_PARSER_H





